#include "raylib.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <sys/wait.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>

#define WIN_WIDTH 800
#define WIN_HEIGHT 600
#define PADDING 15
#define FONT_SIZE 40
#define MAX_COMMANDS 4000
#define MAX_INPUT_LEN 128
#define MAX_VISIBLE 10

typedef struct
{
    char name[256];
    bool matched;
} Command;

Command commands[MAX_COMMANDS];
int cmd_count = 0;
char input[MAX_INPUT_LEN] = "";
int cursor_pos = 0;
int selected_idx = 0;
int scroll_offset = 0;
bool running = true;
pid_t child_pid = -1;
Font app_font;

bool is_duplicate(const char *name)
{
    for (int i = 0; i < cmd_count; i++)
    {
        if (strcmp(commands[i].name, name) == 0)
            return true;
    }
    return false;
}

void load_commands()
{
    char buf[512];
    cmd_count = 0;
    while (cmd_count < MAX_COMMANDS)
    {
        ssize_t len = read(STDIN_FILENO, buf, sizeof(buf) - 1);
        if (len <= 0)
            break;
        buf[len] = '\0';
        char *line = strtok(buf, "\n");
        while (line && cmd_count < MAX_COMMANDS)
        {
            size_t line_len = strlen(line);
            while (line_len > 0 && isspace((unsigned char)line[line_len - 1]))
            {
                line[--line_len] = '\0';
            }
            if (line_len > 0 && !is_duplicate(line))
            {
                strncpy(commands[cmd_count].name, line, sizeof(commands[cmd_count].name) - 1);
                commands[cmd_count].matched = true;
                cmd_count++;
            }
            line = strtok(NULL, "\n");
        }
    }
}

void filter_commands()
{
    int input_len = strlen(input);
    if (input_len == 0)
    {
        for (int i = 0; i < cmd_count; i++)
            commands[i].matched = true;
        selected_idx = cmd_count > 0 ? 0 : -1;
        scroll_offset = 0;
        return;
    }
    int first_match = -1;
    for (int i = 0; i < cmd_count; i++)
    {
        bool match = true;
        for (int j = 0; j < input_len; j++)
        {
            if (tolower((unsigned char)commands[i].name[j]) != tolower((unsigned char)input[j]))
            {
                match = false;
                break;
            }
        }
        commands[i].matched = match;
        if (match && first_match == -1)
            first_match = i;
    }
    selected_idx = (first_match == -1) ? -1 : first_match;
    scroll_offset = selected_idx - (MAX_VISIBLE / 2);
    if (scroll_offset < 0)
        scroll_offset = 0;
}

void execute_command(const char *cmd)
{
    if (!cmd || !*cmd)
        return;
    child_pid = fork();
    if (child_pid == -1)
    {
        perror("fork failed");
        return;
    }
    if (child_pid == 0)
    {
        int null_fd = open("/dev/null", O_RDWR);
        if (null_fd != -1)
        {
            dup2(null_fd, STDIN_FILENO);
            dup2(null_fd, STDOUT_FILENO);
            dup2(null_fd, STDERR_FILENO);
            if (null_fd > 2)
                close(null_fd);
        }
        char *args[64];
        int arg_idx = 0;
        char *token = strtok((char *)cmd, " ");
        while (token && arg_idx < 63)
        {
            args[arg_idx++] = token;
            token = strtok(NULL, " ");
        }
        args[arg_idx] = NULL;
        execvp(args[0], args);
        exit(EXIT_FAILURE);
    }
}

void handle_input()
{
    // 检查Ctrl键状态（Emacs风格快捷键基础）
    bool ctrl_pressed = IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL);

    if (child_pid != -1)
    {
        int status;
        pid_t result = waitpid(child_pid, &status, WNOHANG);
        if (result == child_pid)
        {
            running = false;
        }
        return;
    }

    if (IsKeyPressed(KEY_ESCAPE))
    {
        running = false;
        return;
    }

    // Emacs风格快捷键：Ctrl+P（上一项）
    if (ctrl_pressed && IsKeyPressed(KEY_P))
    {
        if (selected_idx != -1)
        {
            int prev = selected_idx - 1;
            while (prev >= 0 && !commands[prev].matched)
                prev--;
            if (prev >= 0)
            {
                selected_idx = prev;
                scroll_offset = selected_idx - (MAX_VISIBLE / 2);
                if (scroll_offset < 0)
                    scroll_offset = 0;
            }
        }
        return;
    }

    // Emacs风格快捷键：Ctrl+N（下一项）
    if (ctrl_pressed && IsKeyPressed(KEY_N))
    {
        if (selected_idx != -1)
        {
            int next = selected_idx + 1;
            while (next < cmd_count && !commands[next].matched)
                next++;
            if (next < cmd_count)
            {
                selected_idx = next;
                scroll_offset = selected_idx - (MAX_VISIBLE / 2);
                if (scroll_offset < 0)
                    scroll_offset = 0;
            }
        }
        return;
    }

    // Emacs风格快捷键：Ctrl+F（光标右移）
    if (ctrl_pressed && IsKeyPressed(KEY_F))
    {
        if (cursor_pos < strlen(input))
            cursor_pos++;
        return;
    }

    // Emacs风格快捷键：Ctrl+B（光标左移）
    if (ctrl_pressed && IsKeyPressed(KEY_B))
    {
        if (cursor_pos > 0)
            cursor_pos--;
        return;
    }

    // Emacs风格快捷键：Ctrl+A（光标到行首）
    if (ctrl_pressed && IsKeyPressed(KEY_A))
    {
        cursor_pos = 0;
        return;
    }

    // Emacs风格快捷键：Ctrl+E（光标到行尾）
    if (ctrl_pressed && IsKeyPressed(KEY_E))
    {
        cursor_pos = strlen(input);
        return;
    }

    // Emacs风格快捷键：Ctrl+D（删除光标后字符）
    if (ctrl_pressed && IsKeyPressed(KEY_D))
    {
        if (cursor_pos < strlen(input))
        {
            memmove(&input[cursor_pos], &input[cursor_pos + 1], MAX_INPUT_LEN - cursor_pos - 1);
            filter_commands();
        }
        return;
    }

    // Emacs风格快捷键：Ctrl+K（删除到行尾）
    if (ctrl_pressed && IsKeyPressed(KEY_K))
    {
        input[cursor_pos] = '\0';
        filter_commands();
        return;
    }

    int key = GetCharPressed();
    while (key > 0)
    {
        if (key >= 32 && key <= 126 && strlen(input) < MAX_INPUT_LEN - 1)
        {
            memmove(&input[cursor_pos + 1], &input[cursor_pos], MAX_INPUT_LEN - cursor_pos - 1);
            input[cursor_pos++] = (char)key;
            filter_commands();
        }
        key = GetCharPressed();
    }

    if (IsKeyPressed(KEY_BACKSPACE) && cursor_pos > 0)
    {
        cursor_pos--;
        memmove(&input[cursor_pos], &input[cursor_pos + 1], MAX_INPUT_LEN - cursor_pos - 1);
        filter_commands();
    }

    if (IsKeyPressed(KEY_DOWN) && selected_idx != -1)
    {
        int next = selected_idx + 1;
        while (next < cmd_count && !commands[next].matched)
            next++;
        if (next < cmd_count)
        {
            selected_idx = next;
            scroll_offset = selected_idx - (MAX_VISIBLE / 2);
            if (scroll_offset < 0)
                scroll_offset = 0;
        }
    }

    if (IsKeyPressed(KEY_UP) && selected_idx != -1)
    {
        int prev = selected_idx - 1;
        while (prev >= 0 && !commands[prev].matched)
            prev--;
        if (prev >= 0)
        {
            selected_idx = prev;
            scroll_offset = selected_idx - (MAX_VISIBLE / 2);
            if (scroll_offset < 0)
                scroll_offset = 0;
        }
    }

    if (IsKeyPressed(KEY_RIGHT) && cursor_pos < strlen(input))
        cursor_pos++;
    if (IsKeyPressed(KEY_LEFT) && cursor_pos > 0)
        cursor_pos--;
    if (IsKeyPressed(KEY_HOME))
        cursor_pos = 0;
    if (IsKeyPressed(KEY_END))
        cursor_pos = strlen(input);

    if (IsKeyPressed(KEY_ENTER))
    {
        if (selected_idx != -1 && commands[selected_idx].matched)
        {
            execute_command(commands[selected_idx].name);
        }
        else if (strlen(input) > 0)
        {
            execute_command(input);
        }
    }

    // 鼠标滚轮导航（与rmenu.c行为一致：直接改变选中项）
    float wheel = GetMouseWheelMove();
    if (wheel != 0 && selected_idx != -1)
    {
        int center_pos = MAX_VISIBLE / 2;
        if (wheel > 0) // 上滚：选中上一项
        {
            int prev_idx = selected_idx - 1;
            while (prev_idx >= 0 && !commands[prev_idx].matched)
                prev_idx--;
            if (prev_idx >= 0)
            {
                selected_idx = prev_idx;
                scroll_offset = selected_idx - center_pos;
                scroll_offset = (scroll_offset < 0) ? 0 : scroll_offset;
            }
        }
        else // 下滚：选中下一项
        {
            int next_idx = selected_idx + 1;
            while (next_idx < cmd_count && !commands[next_idx].matched)
                next_idx++;
            if (next_idx < cmd_count)
            {
                selected_idx = next_idx;
                scroll_offset = selected_idx - center_pos;
                scroll_offset = (scroll_offset < 0) ? 0 : scroll_offset;
            }
        }
    }
}

void render()
{
    BeginDrawing();
    ClearBackground(BLACK);
    DrawRectangle(PADDING, PADDING, WIN_WIDTH - 2 * PADDING, FONT_SIZE + 10, (Color){40, 40, 40, 255});
    const char *prompt = "Filter > ";
    DrawTextEx(app_font, prompt, (Vector2){PADDING + 5, PADDING + 5}, FONT_SIZE, 1, WHITE);
    float prompt_width = MeasureTextEx(app_font, prompt, FONT_SIZE, 1).x;
    DrawTextEx(app_font, input, (Vector2){PADDING + 5 + prompt_width, PADDING + 5}, FONT_SIZE, 1, YELLOW);
    static bool cursor_visible = true;
    static double last_cursor_flip = 0;
    if (GetTime() - last_cursor_flip > 0.5)
    {
        cursor_visible = !cursor_visible;
        last_cursor_flip = GetTime();
    }
    if (cursor_visible)
    {
        char cursor_part[MAX_INPUT_LEN];
        strncpy(cursor_part, input, cursor_pos);
        cursor_part[cursor_pos] = '\0';
        float cursor_x = prompt_width + PADDING + 5 + MeasureTextEx(app_font, cursor_part, FONT_SIZE, 1).x;
        DrawRectangle(cursor_x, PADDING + 5, 2, FONT_SIZE, WHITE);
    }
    int separator_y = PADDING + FONT_SIZE + 20;
    DrawLine(PADDING, separator_y, WIN_WIDTH - PADDING, separator_y, GRAY);
    int y = separator_y + 10;
    int visible = 0;
    for (int i = 0; i < cmd_count && visible < MAX_VISIBLE; i++)
    {
        if (commands[i].matched && i >= scroll_offset)
        {
            if (i == selected_idx)
            {
                DrawRectangle(PADDING, y - 2, WIN_WIDTH - 2 * PADDING, FONT_SIZE + 5, (Color){0, 100, 200, 200});
            }
            DrawTextEx(app_font, commands[i].name, (Vector2){PADDING + 10, y}, FONT_SIZE, 1, WHITE);
            y += FONT_SIZE + 8;
            visible++;
        }
    }
    DrawTextEx(app_font, "Enter: Execute | Esc: Quit | PgUp|PgDn: Navigate",
               (Vector2){PADDING, WIN_HEIGHT - PADDING - FONT_SIZE},
               FONT_SIZE - 4, 1, LIGHTGRAY);
    EndDrawing();
}

int main()
{
    InitWindow(WIN_WIDTH, WIN_HEIGHT, "rfzf");
    SetTargetFPS(60);
    const char *font_paths[] = {
        "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
        "/usr/share/fonts/truetype/ubuntu/Ubuntu-R.ttf",
        "/usr/share/fonts/corefonts/arial.ttf"};
    app_font = GetFontDefault();
    for (int i = 0; i < sizeof(font_paths) / sizeof(font_paths[0]); i++)
    {
        Font temp = LoadFont(font_paths[i]);
        if (temp.baseSize > 0)
        {
            app_font = temp;
            break;
        }
    }
    load_commands();
    filter_commands();
    while (running && !WindowShouldClose())
    {
        handle_input();
        render();
    }
    UnloadFont(app_font);
    CloseWindow();
    return 0;
}
